/* 
 * Thx to Michael Schwarz
 * for good eksamples at 
 *  http://weblogs.asp.net/mschwarz/archive/2008/03/09/wrong-datetime-on-net-micro-framework-devices.aspx
 *  
 * Other possibilities to get networked time
 * http://www.jaypm.com/2011/09/setting-the-netduinos-datetime-automatically/
 *
 * time serverhttp://www.pool.ntp.org/zone/dk
*/

using System;
using System.Net;
using System.Net.Sockets;
using Microsoft.SPOT;

namespace DaaseVarmer.helperClasses.networkComponents
{
    public class TimeHelper : IDisposable
    {
        private Boolean _isRealTime;

        public TimeHelper()
        {
             _isRealTime = false;
        }


        public Boolean isRealTime ()
        {
            return _isRealTime;
        }

        /* 
         * Thx to Michael Schwarz
         * for good eksamples at 
         *  http://weblogs.asp.net/mschwarz/archive/2008/03/09/wrong-datetime-on-net-micro-framework-devices.aspx 
         */
        public DateTime GetNetworkTime()
        {
            DateTime dateTime = new DateTime(1900, 1, 1);
            DateTime networkDateTime = dateTime;

            try
            {
                IPEndPoint ep = new IPEndPoint(Dns.GetHostEntry("time-a.nist.gov").AddressList[0], 123);
                Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                s.SendTimeout = s.ReceiveTimeout = 10000;
                s.Connect(ep);

                byte[] ntpData = new byte[48]; // RFC 2030
                ntpData[0] = 0x1B;
                for (int i = 1; i < 48; i++)
                    ntpData[i] = 0;

                s.Send(ntpData);
                s.Receive(ntpData);

                byte offsetTransmitTime = 40;
                ulong intpart = 0;
                ulong fractpart = 0;
                for (int i = 0; i <= 3; i++)
                    intpart = 256 * intpart + ntpData[offsetTransmitTime + i];

                for (int i = 4; i <= 7; i++)
                    fractpart = 256 * fractpart + ntpData[offsetTransmitTime + i];

                ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);

                s.Close();

                TimeSpan timeSpan = TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond);           
                dateTime += timeSpan;
                TimeSpan offsetAmount = TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);
                networkDateTime = (dateTime + offsetAmount);

                Debug.Print(networkDateTime.ToString());
                _isRealTime = true;
                //todo event-log network Time found [time]
            } 
            catch (Exception e)
            {
                Debug.Print("network time not set");
            }
            
           
            return networkDateTime;
        }

    public bool UpdateTimeFromNtpServer(string server, int timeZoneOffset)
    {
        try
        {
            var currentTime = GetNtpTime(server, timeZoneOffset);
            Microsoft.SPOT.Hardware.Utility.SetLocalTime(currentTime);
 
            return true;
        }
        catch
        {
            return false;
        }
    }
 
    /// <summary>
    /// Get DateTime from NTP Server
    /// Based on:
    /// http://weblogs.asp.net/mschwarz/archive/2008/03/09/wrong-datetime-on-net-micro-framework-devices.aspx
    /// </summary>
    /// <param name="timeServer">Time Server (NTP) address</param>
    /// <param name="timeZoneOffset">Difference in hours from UTC</param>
    /// <returns>Local NTP Time</returns>
    private static DateTime GetNtpTime(String timeServer, int timeZoneOffset)
    {
        // Find endpoint for TimeServer
        var ep = new IPEndPoint(Dns.GetHostEntry(timeServer).AddressList[0], 123);
 
        // Make send/receive buffer
        var ntpData = new byte[48];
 
        // Connect to TimeServer
        using (var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
        {
            // Set 10s send/receive timeout and connect
            s.SendTimeout = s.ReceiveTimeout = 10000; // 10,000 ms
            s.Connect(ep);
 
            // Set protocol version
            ntpData[0] = 0x1B;
 
            // Send Request
            s.Send(ntpData);
 
            // Receive Time
            s.Receive(ntpData);
 
            // Close the socket
            s.Close();
        }
 
        const byte offsetTransmitTime = 40;
 
        ulong intpart = 0;
        ulong fractpart = 0;
 
        ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);
 
        var timeSpan = TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond);
        var dateTime = new DateTime(1900, 1, 1);
        dateTime += timeSpan;
 
        var offsetAmount = new TimeSpan(timeZoneOffset, 0, 0);
        var networkDateTime = (dateTime + offsetAmount);
 
        return networkDateTime;
    }

        //public DateTime GetRealTimeFromDevice()
        //{
        //  when the I2C realtime device is connected implement this function
        //}

        public void Dispose()
        {
            //throw new NotImplementedException();
        }

    }
}
